use crate::cli::verify_file;
use crate::{process_generate_key, process_text_sign, process_text_verify, CmdExecutor};
use clap::Parser;
use enum_dispatch::enum_dispatch;
use std::path::PathBuf;
use std::str::FromStr;
use std::{fmt, fs};

#[derive(Debug, Parser)]
#[enum_dispatch(CmdExecutor)]
pub enum TextSubCommand {
    #[command(name = "sign", about = "Sign text")]
    Sign(TextSignOpts),
    #[command(name = "verify", about = "Verify signature")]
    Verify(TextVerifyOpts),
    #[command(name = "generate_key", about = "Generate key")]
    Generate(TextGenerateOpts),
}

#[derive(Debug, Parser)]
pub struct TextSignOpts {
    #[arg(long, value_parser= verify_file,default_value = "-")]
    pub input: String,
    #[arg(long, value_parser= verify_file)]
    pub key: String,
    #[arg(long,value_parser=parse_format ,default_value = "blake3")]
    pub format: TextSignFormat,
}

#[derive(Debug, Parser)]
pub struct TextVerifyOpts {
    #[arg(long, value_parser= verify_file,default_value = "-")]
    pub input: String,
    #[arg(long, value_parser= verify_file)]
    pub key: String,
    #[arg(long,value_parser=parse_format, default_value = "blake3")]
    pub format: TextSignFormat,
    #[arg(long)]
    pub sig: String,
}
#[derive(Debug, Parser)]
pub struct TextGenerateOpts {
    #[arg(long,value_parser=parse_format, default_value = "blake3")]
    pub format: TextSignFormat,
    #[arg(long,value_parser=verify_path)]
    pub output: PathBuf,
}

#[derive(Debug, Clone, Copy)]
pub enum TextSignFormat {
    Blake3,
    Ed25519,
}
pub fn parse_format(format: &str) -> Result<TextSignFormat, String> {
    format.parse()
}

impl FromStr for TextSignFormat {
    type Err = String;
    fn from_str(format: &str) -> Result<Self, Self::Err> {
        match format.to_lowercase().as_str() {
            "blake3" => Ok(TextSignFormat::Blake3),
            "ed25519" => Ok(TextSignFormat::Ed25519),
            _ => Err(format!("Invalid format: {}", format)),
        }
    }
}

impl From<TextSignFormat> for &'static str {
    fn from(format: TextSignFormat) -> Self {
        match format {
            TextSignFormat::Blake3 => "blake3",
            TextSignFormat::Ed25519 => "ed25519",
        }
    }
}
impl fmt::Display for TextSignFormat {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            TextSignFormat::Blake3 => write!(f, "blake3"),
            TextSignFormat::Ed25519 => write!(f, "ed25519"),
        }
    }
}

fn verify_path(path: &str) -> Result<PathBuf, String> {
    let path = PathBuf::from(path);
    if path.exists() {
        Ok(path)
    } else {
        Err(format!("Invalid path: {}", path.display()))
    }
}

impl CmdExecutor for TextVerifyOpts {
    async fn execute(self) -> anyhow::Result<()> {
        let result = process_text_verify(&self.input, &self.key, &self.sig, self.format)?;
        println!("{}", result);
        Ok(())
    }
}

impl CmdExecutor for TextSignOpts {
    async fn execute(self) -> anyhow::Result<()> {
        let sig = process_text_sign(&self.input, &self.key, self.format)?;
        println!("{}", sig);
        Ok(())
    }
}
impl CmdExecutor for TextGenerateOpts {
    async fn execute(self) -> anyhow::Result<()> {
        let key = process_generate_key(self.format)?;
        match self.format {
            TextSignFormat::Blake3 => {
                let name = self.output.join("blake3.txt");
                fs::write(name, &key[0])?;
            }
            TextSignFormat::Ed25519 => {
                let name = self.output.join("ed25519.sk");
                fs::write(name, &key[0])?;
                let name = self.output.join("ed25519.pk");
                fs::write(name, &key[1])?;
            }
        }
        Ok(())
    }
}

// impl CmdExecutor for TextSubCommand {
//     async fn execute(self) -> anyhow::Result<()> {
//         match self {
//             TextSubCommand::Sign(opts) => opts.execute().await,
//             TextSubCommand::Verify(opts) => opts.execute().await,
//             TextSubCommand::Generate(opts) => opts.execute().await,
//         }
//     }
// }
